using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using RideMe.Core;
using System.Diagnostics;

namespace RideMe.Presentation.Controls
{
    public partial class OutputWindow : UserControl
    {
        private List<string> _outputBuffer = new List<string>();

        private const int NumberOfLinesToBuffer = 5;

        /// <summary>
        /// Initializes a new instance of the <see cref="T:OutputWindow"/> class.
        /// </summary>
        public OutputWindow()
        {
            InitializeComponent();
            HookProjectServiceEvents();
        }

        private void HookProjectServiceEvents()
        {
            ProjectService.OutputReceived += new EventHandler<DataReceivedEventArgs>(ProjectService_OutputReceived);
            ProjectService.ProjectClosed += new EventHandler(ProjectService_ProjectClosed);
        }

        private void UnhookProjectServiceEvents()
        {
            ProjectService.OutputReceived -= new EventHandler<DataReceivedEventArgs>(ProjectService_OutputReceived);
            ProjectService.ProjectClosed -= new EventHandler(ProjectService_ProjectClosed);
        }

        /// <summary>
        /// Gets the output text.
        /// </summary>
        /// <value>The output text.</value>
        public string OutputText
        {
            get { return outputTextBox.Text; }
        }


        /// <summary>
        /// Appends the output.
        /// </summary>
        /// <param name="output">The output.</param>
        public void AppendOutput(string output)
        {
            if (outputTextBox.InvokeRequired)
            {
                Invoke(new MethodInvoker(
                        delegate()
                        {
                            AppendOutput(output);
                        }));
            }
            else
            {
                // Buffer output so the app doesn't hang when a lot
                // of output comes in (i.e. Mongrel).
                if (_outputBuffer.Count >= NumberOfLinesToBuffer)
                {
                    foreach (string line in _outputBuffer)
                    {
                        outputTextBox.Text += line;
                    }
                    // Scroll to the bottom as output comes in.
                    outputTextBox.SelectionStart = outputTextBox.Text.Length;
                    outputTextBox.SelectionLength = 0;
                    outputTextBox.ScrollToCaret();
                    _outputBuffer.Clear();
                }
                else
                {
                    _outputBuffer.Add(output + Environment.NewLine);
                }
            }
        }

        /// <summary>
        /// Handles the OutputReceived event of the ProjectService control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="T:System.Diagnostics.DataReceivedEventArgs"/> instance containing the event data.</param>
        private void ProjectService_OutputReceived(object sender, DataReceivedEventArgs e)
        {
            AppendOutput(e.Data);
        }


        /// <summary>
        /// Handles the ProjectClosed event of the ProjectService control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="T:System.EventArgs"/> instance containing the event data.</param>
        private void ProjectService_ProjectClosed(object sender, EventArgs e)
        {
            ClearOutput();
        }

        /// <summary>
        /// Clears the output.
        /// </summary>
        public void ClearOutput()
        {
            if (outputTextBox.InvokeRequired)
            {
                Invoke(new MethodInvoker(
                    delegate()
                    {
                        ClearOutput();
                    }));
            }
            else
            {
                outputTextBox.Clear();
            }
        }

        private void outputTextBox_KeyDown(object sender, KeyEventArgs e)
        {
            if ((ModifierKeys & Keys.Control) != 0)
            {
                switch (e.KeyCode)
                {
                    case Keys.A: ((TextBox)sender).SelectAll();
                        break;
                    case Keys.X: ((TextBox)sender).Cut();
                        break;
                    case Keys.C: ((TextBox)sender).Copy();
                        break;
                    case Keys.V: ((TextBox)sender).Paste();
                        break;
                }
            }
        }
    }
}
